package net.yla.smartbus.core.util;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.fastjson.JSON;
import net.yla.smartbus.core.base.BaseController;
import net.yla.smartbus.module.ba.right.login.dto.UserSession;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.rmi.runtime.Log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.xml.transform.Source;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;


/**
 * @author Handy Wong
 * @date 2019/9/10 14:36
 */

@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
})
public class SqlInterceptor extends BaseController implements Interceptor {

   /* @Autowired
    LogService logService;*/


    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 换行符
     **/
    public static final String N = "\n";
    /**
     * tab符
     **/
    public static final String T = "\t";
    /**
     * 空格
     **/
    public static final String BLANK = " ";
    /**
     * 双空格
     **/
    public static final String DOUBLE_BLANK = "  ";
    /**
     * sql限定长度
     **/
    public static final int LEN = 1000;

    private boolean flag = false;


    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    int i = 0;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        Object target = invocation.getTarget();

        if (target instanceof Executor) {
            long start = System.currentTimeMillis();
            Method method = invocation.getMethod();
            /**执行方法*/

            long end = System.currentTimeMillis();
            final Object[] args = invocation.getArgs();
            //查询描述
            String descrip = "";
            //获取原始的ms
            MappedStatement ms = (MappedStatement) args[0];
            Configuration configuration = ms.getConfiguration();
            String commandName = ms.getSqlCommandType().name();
            String name = method.getName();
            System.out.println(name);
            System.out.println(commandName);
            boolean flaf=true;
            Integer op = null;
            if (commandName.startsWith("INSERT")) {
                name += "=新增";
                descrip = "新增操作";
                op = 1;
            } else if (commandName.startsWith("UPDATE")) {
                name += "=修改";
                descrip = "修改操作";
                op = 2;
            } else if (commandName.startsWith("DELETE")) {
                name += "=删除";
                descrip = "删除操作";
                op = 3;
            } else if (commandName.startsWith("SELECT")) {
                flaf=false;
                name += "=查询";
                descrip = "查询操作";
                op = 0;
            }
            String message = "[SqlInterceptor] execute [" + name + "] cost [" + (end - start) + "] ms";
            logger.info(message);
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append(message);
            stringBuffer.append("\n");
            DruidDataSource dataSource = (DruidDataSource) configuration.getEnvironment().getDataSource();
            //当前用户的IP地址
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String ipaddress = request.getRemoteAddr();
            Object parameterObject = args[1];
            BoundSql boundSql = ms.getBoundSql(parameterObject);
         List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            //获取条件参数列表
            String parameterObjects = JSON.toJSONString(boundSql.getParameterObject());
            HttpSession session = request.getSession();
            //获取执行的sql
            String sql = boundSql.getSql();
            //获取数据库类型
            String dbType = dataSource.getDataSourceStat().getDbType();
            sql=this.trim(sql);
            sql = this.formatSQL(sql,dbType,parameterObjects);
            logger.info("当前执行的sql为:"+sql);
//            System.out.println("执行的sql" + sql);
//            System.out.println("参数" + parameterObjects);

            //获取当前拦截的方法名
            String id = ms.getId();

            //获取token关键字
            String token = this.getToken();
            String[] tokenFlag = null;
            boolean jcxtFlag = false;
            if (null != token) {
                tokenFlag = token.split("_");
                for (String str : tokenFlag) {
                    //只记录基础系统的请求
                    if (str.equals("jcsl")) {
                        jcxtFlag = true;
                        break;
                    }
                }
            }
            //EB751B3000DA436CB1BD93F6984B4FF1_jcsl_3037
            if (jcxtFlag&&flaf) {
                    insertSyslog(token, session, sql, parameterObjects, descrip, ipaddress);
            }

        }

        return invocation.proceed();


    }

    protected void insertSyslog(String token, HttpSession session, String sql, String parameterObjects, String descrip, String ipaddress) {
        //与前一次sql跟参数作比较,如果是同一操作就不记录
        String oldSql = (String) session.getAttribute("sql");
        String oldParams = (String) session.getAttribute("form");
        boolean flagSix = sql.equals(oldSql);
        boolean flagSeven = parameterObjects.equals(oldParams);

        if (null != token) {
            if (!flagSeven && !flagSix) {
                token = StringUtils.remove(token.substring(token.lastIndexOf("_")), "_");
                Integer userIdone = Integer.valueOf(token);
                //重新写入
                session.setAttribute("userId", userIdone);
                session.setAttribute("sql", sql);
                session.setAttribute("form", parameterObjects);
                session.setAttribute("descript", descrip);
                session.setAttribute("ipAdress", ipaddress);
                //获取
                Integer userId = (Integer) session.getAttribute("userId");
                String nowSql = (String) session.getAttribute("sql");
                String param = (String) session.getAttribute("form");
                String ip = (String) session.getAttribute("ipAdress");
                String descri = (String) session.getAttribute("descript");
                //设置参数准备记录到数据库

                //暂时不开放日志功能********************
/*                Test FieldOfVisionQuery = new Test();
                FieldOfVisionQuery.insertSyslog(sysLogDO);*/
            }
        }
    }


    @Override
    public Object plugin(Object obj) {
        //        只拦截Executor对象,减少目标被代理的次数
        if (obj instanceof Executor) {
            return Plugin.wrap(obj, this);
        }
        return obj;
    }

    @Override
    public void setProperties(Properties arg0) {
    }
//去除多余空格啥的

    private String trim(String sql) {
        if (StringUtils.isBlank(sql)) {
            return "执行sql为空";
        }
        sql = sql.trim();
        while (sql.indexOf(N) != -1) {
            sql = sql.replaceAll(N, BLANK);
        }
        while (sql.indexOf(T) != -1) {
            sql = sql.replaceAll(T, BLANK);
        }
        while (sql.indexOf(DOUBLE_BLANK) != -1) {
            sql = sql.replaceAll(DOUBLE_BLANK, BLANK);
        }
        return sql;
    }
    public String formatSQL(String src, String dbType, String params) {
        //要传入的SQLUtils的参数集合,实际上虽然泛型是Object,但其实都是基本数据类型
        List<Object> paramList = new ArrayList();
        //有了JSON字符串我们就可以通过正则表达式得到参数了

        //需要注意的是这个SQLUtils是Druid数据源中的一个工具类,因为有现成的拼sql的工具,所以我就不再重复造轮子了,如果你的项目并没有使用Druid,
        //则需要将这个工具类加入到你的项目中
        String retSQL = SQLUtils.format(src, dbType, paramList);
        return retSQL;
    }


}
